


import tkinter
import tkinter.ttk
import serial
import serial.tools.list_ports
from draw import draw_static,draw_active,setdraw
import time
from threading import Thread




#-------------------分割线---------------------设置窗口
win=tkinter.Tk()
win.title("简易串口通信程序")
win.geometry("745x554")
win.configure(bg="#d2d2d2")
win.resizable(False,False)
#-------------------分割线---------------------设置配置变量
comname =tkinter.StringVar()#串口名
bdrate=tkinter.StringVar()#波特率
btrate=tkinter.StringVar()#数据位
strate=tkinter.StringVar()#停止位
parate=tkinter.StringVar()#校验位
showmode=tkinter.StringVar()#显示模式
datalong=tkinter.StringVar()#数据长度
sendtext=tkinter.StringVar()#发送的文本
#-------------------分割线---------------------设置标签
Label_2 = tkinter.Label(win,text="串口列表",width = 10,height = 4)
Label_2.place(x = 18,y = 8,width = 100,height = 20)
Label_2.configure(relief = "groove")
Label_4 = tkinter.Label(win,text="波特率",width = 10,height = 4)
Label_4.place(x = 18,y = 59,width = 100,height = 20)
Label_4.configure(relief = "groove")
Label_6 = tkinter.Label(win,text="数据位",width = 10,height = 4)
Label_6.place(x = 16,y = 112,width = 100,height = 20)
Label_6.configure(relief = "groove")
Label_8 = tkinter.Label(win,text="停止位",width = 10,height = 4)
Label_8.place(x = 15,y = 163,width = 100,height = 20)
Label_8.configure(relief = "groove")
Label_10 = tkinter.Label(win,text="校验位",width = 10,height = 4)
Label_10.place(x = 15,y = 216,width = 100,height = 20)
Label_10.configure(relief = "groove")
Label_13 = tkinter.Label(win,text="接收区",width = 10,height = 4)
Label_13.place(x = 188,y = 7,width = 100,height = 20)
Label_13.configure(relief = "groove")
Label_15 = tkinter.Label(win,text="显示模式",width = 10,height = 4)
Label_15.place(x = 190,y = 30,width = 100,height = 20)
Label_15.configure(relief = "flat")
Label_20 = tkinter.Label(win,text="绘图数据个数",width = 10,height = 4)
#Label_20.place(x = 618,y = 7,width = 100,height = 20)
Label_20.configure(relief = "groove")
Label_25 = tkinter.Label(win,text="发送区",width = 10,height = 4)
Label_25.place(x = 192,y = 370,width = 100,height = 20)
Label_25.configure(relief = "groove")
#-------------------分割线---------------------设置文本框
Text_12 = tkinter.Text(win)
Text_12.place(x = 190,y = 59,width = 546,height = 246)
Text_12.configure(relief = "groove")
#-------------------分割线---------------------设置输入框验证函数
#def entry_ok(data):
#    return data.isdigit()
#win.register(entry_ok)
#-------------------分割线---------------------设置输入框
#Entry_1 = tkinter.Entry(win,textvariable=datalong,validate="key",validatecommand=(entry_ok,'%P'))#输入数据长度
#Entry_1.place(x = 618,y = 30,width = 100,height = 20)
Entry_1 = tkinter.Entry(win,textvariable=datalong)
Entry_1.configure(relief = "sunken")
Entry_1.insert("insert","1000")
Entry_2 = tkinter.Entry(win,textvariable=sendtext)#输入发送的数据
Entry_2.place(x = 190,y = 394,width = 547,height = 83)
Entry_2.configure(relief = "sunken")
#-------------------分割线---------------------设置选择框
bd = tkinter.ttk.Combobox(win,textvariable=bdrate, state="readonly")#选择波特率
bd.place(x = 19,y = 79,width = 100,height = 20)
bd["values"]=['300','600','1200','1800','2400','4800','9600','19200','38400','57600','115200',"230400", "460800", "500000", "576000", "921600"]
bd.current(11)
bt = tkinter.ttk.Combobox(win,textvariable=btrate, state="readonly")#选择数据位
bt.place(x = 16,y = 129,width = 100,height = 20)
bt["values"]=['5','6','7','8']
bt.current(3)
st = tkinter.ttk.Combobox(win,textvariable=strate, state="readonly")#选择停止位
st.place(x = 15,y = 183,width = 100,height = 20)
st["values"]=['1','1.5','2']
st.current(0)
pa = tkinter.ttk.Combobox(win,textvariable=parate, state="readonly")#选择校验位
pa.place(x = 16,y = 235,width = 100,height = 20)
pa.configure(state = "readonly")
pa["values"]=['None','Even','Odd','Mark','Space']
pa.current(0)
comlist = tkinter.ttk.Combobox(win,textvariable=comname, state="readonly")
comlist.place(x = 19,y = 27,width = 100,height = 20)
#-------------------分割线---------------------设置按钮函数
com_status=False#串口状态
pic_status=False#示波器状态
com=None
x_time=[]
y_ad=[]
def clear_text():
    Text_12.delete(1.0,"end")
def comreceive_GUI(showmode:tkinter.StringVar,datalong:tkinter.StringVar):#接收函数
    global com_status,x_time,y_ad,com
    while com_status:
        if com is not None and datalong.get().isdigit() :
            if com.is_open and com.in_waiting:
                if showmode.get()=="text":
                    text=com.read(com.in_waiting).decode("utf-8",errors="ignore")
                elif showmode.get()=="hex":
                    text=com.read(com.in_waiting).hex()
                elif showmode.get()=="pic":#图像模式接收“%ld，%hu\r\n”的数据格式，其中ld为采样周期*100000，hu是ADC的原始数据
                    try:
                        text=com.readline().decode("utf-8",errors="ignore")
                        text=text.split(",")
                        x_n=round(int(text[0])/100000,5)
                        y_n=round(int(text[1])*3.3/4096,2)
                        if len(x_time)!=0:#数据检查函数
                            if abs(x_n-x_time[-1])>2:
                                Text_12.insert("end","error\n")#打印接收的数据
                                continue
                        text="(%.5f,%.2f)\n"%(x_n,y_n) 
                    except Exception as e:
                        text="数据格式错误"+str(e)
                        Text_12.insert("end",text)#打印接收的数据
                        continue
                    y_ad.append(y_n)
                    x_time.append(x_n)
                    while len(y_ad)>int(datalong.get()):
                        del x_time[0],y_ad[0]
                else:
                    continue
                Text_12.insert("end",text)#打印接收的数据
    x_time.clear()
    y_ad.clear()
def combuild_GUI():#打开串口按钮
    global com_status,com
    if com_status:#如果串口开启
        com.close()
        Text_12.insert("end","串口关闭成功\n")
        com_status=False
        comlist["values"]=[x[0] for x in serial.tools.list_ports.comports()]#查找可用串口
    else:#如果串口关闭
        me={"None":serial.PARITY_NONE,"Odd":serial.PARITY_ODD,"Even":serial.PARITY_EVEN,"Mark":serial.PARITY_MARK,"Space":serial.PARITY_SPACE}
        clear_text()
        try:
            com=serial.Serial(comname.get(),baudrate=int(bdrate.get()),bytesize=int(btrate.get()),stopbits=int(strate.get()),parity=me[parate.get()],timeout=2)
            Text_12.insert("end","串口开启成功\n")
            re_t=Thread(target=comreceive_GUI,args=(showmode,datalong))#开始监听串口
            com_status=True
            re_t.start()
        except Exception as e:
            Text_12.insert("end","串口开启失败:"+str(e)+"\n")
def comwrite_GUI():#数据发送函数
    global com,sendtext
    if com is not None and sendtext.get()!="" and sendtext.get().isalnum():
        if com.is_open:
                longth=com.write(sendtext.get().encode("utf-8"))
def draw():#示波器模式按钮
    global x_time,y_ad,pic_status
    if pic_status:
        pic_status=False
        setdraw(pic_status)
    else:
        pic_status=True
        setdraw(pic_status)
        draw_active(x_time,y_ad)

def draw_s():
    global x_time,y_ad
    draw_static(x_time,y_ad)           


#-------------------分割线---------------------设置按钮
open = tkinter.Button(win,text="打开\关闭串口",width = 10,height = 4,command=combuild_GUI)
open.place(x = 12,y = 277,width = 104,height = 37)
FFT_botton = tkinter.Button(win,text="FFT",width = 10,height = 4,command=draw_s)
#FFT_botton.place(x = 187,y = 314,width = 136,height = 46)
show_botton = tkinter.Button(win,text="示波器模式",width = 10,height = 4,command=draw)
#show_botton.place(x = 363,y = 314,width = 136,height = 46)
sendb = tkinter.Button(win,text="发送",width = 10,height = 4,command=comwrite_GUI)
sendb.place(x = 191,y = 492,width = 137,height = 43)
clr=tkinter.Button(win,text="清空接收区",width = 10,height = 4,command=clear_text)
clr.place(x=12,y=330,width = 104,height = 37)
#-------------------分割线---------------------设置接收设置选择函数

def on_text():#文本模式选项命令
    Label_20.place_forget()#隐藏“绘图数据个数”
    Entry_1.place_forget()#隐藏“数据长度输入框”
    FFT_botton.place_forget()#隐藏“FFT”按钮
    show_botton.place_forget()#隐藏“示波器”按钮
def on_hex():#十六进制模式命令
    Label_20.place_forget()#隐藏“绘图数据个数”
    Entry_1.place_forget()#隐藏“数据长度输入框”
    FFT_botton.place_forget()#隐藏“FFT”按钮
    show_botton.place_forget()#隐藏“示波器”按钮
def on_pic():#图像模式命令
    FFT_botton.place(x = 187,y = 314,width = 136,height = 46)#显示“FFT”按钮
    show_botton.place(x = 363,y = 314,width = 136,height = 46)#显示“示波器”按钮
    Entry_1.place(x = 618,y = 30,width = 100,height = 20)#显示“数据长度”输入框
    Label_20.place(x = 618,y = 7,width = 100,height = 20)#显示“绘图数据个数”
#-------------------分割线---------------------设置接收显示选择
Radiobutton_1 = tkinter.Radiobutton(win,variable=showmode,value="text",text="文本模式",anchor=tkinter.W,command=on_text)
Radiobutton_1.place(x = 298,y = 30,width = 100,height = 20)
Radiobutton_2 = tkinter.Radiobutton(win,variable=showmode,value="hex",text="十六进制模式",anchor=tkinter.W,command=on_hex)
Radiobutton_2.place(x = 407,y = 30,width = 100,height = 20)
RadioButton_3 = tkinter.Radiobutton(win,variable=showmode,value="pic",text="绘图模式",anchor=tkinter.W,command=on_pic)
RadioButton_3.place(x = 515,y = 30,width = 100,height = 20)
#-------------------分割线---------------------查找串口

comlist["values"]=[x[0] for x in serial.tools.list_ports.comports()]#查找可用串口
#-------------------分割线---------------------

win.mainloop()